package com.gk.panda.gateway.filter;

import com.gk.panda.commons.rsa.RsaService;
import com.gk.panda.gateway.service.UserService;
import com.gk.panda.pojo.UrlInfo;
import com.gk.panda.gateway.util.ResponseUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ValueOperations;
import org.springframework.http.HttpHeaders;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.http.server.reactive.ServerHttpResponse;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

import java.net.URLEncoder;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;

@Component
public class AuthorizationFilter implements GlobalFilter, Ordered {

    private static final List<UrlInfo> EXCLUDE_URLS = Arrays.asList(
            new UrlInfo("/kaptcha","get"),
            new UrlInfo("/file/upload","post"),
            new UrlInfo("/file/del","get"),
            new UrlInfo("/file/download","post"),
            new UrlInfo("/edmp/largeScreen/getLoginBack","get"),
            new UrlInfo("/edmp/largeScreen/downloadPatrolAPPUrl","get"),
            new UrlInfo("/umwcamera/getListOfApp","post")
            );

    @Autowired
    private RsaService rsaService;

    @Autowired
    private UserService userService;

    @Autowired
    private RedisTemplate<String,Object> redisTemplate;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {
        ServerHttpRequest request = exchange.getRequest();
        ServerHttpResponse response = exchange.getResponse();
        String url = request.getPath().value();
        String method = request.getMethod().name().toLowerCase();
        if (comparison(EXCLUDE_URLS,url,method)) {
            return chain.filter(exchange);
        }
        HttpHeaders requestHeaders = request.getHeaders();
        String token = requestHeaders.getFirst("Authorization");
        if (token == null) {
            return ResponseUtil.writeError(response,102,"请先登录");
        }
        try {
            Map<String, Object> map = rsaService.parseToken(token);
            Object orgId = map.get("orgId");
            String orgName = (String) map.get("orgName");
            String username = (String) map.get("username");
            String orgAbbr = (String) map.get("orgAbbr");
            String name = (String) map.get("name");
            String loginWay = (String) map.get("loginWay");
            ServerHttpRequest.Builder builder = request.mutate();
            builder.header("orgId",orgId.toString());
            builder.header("orgName", URLEncoder.encode(orgName, "utf-8"));
            builder.header("username",URLEncoder.encode(username, "utf-8"));
            builder.header("orgAbbr",orgAbbr);
            builder.header("name",URLEncoder.encode(name, "utf-8"));
            ServerHttpRequest newRequest = builder.build();
            ValueOperations<String,Object> ops = redisTemplate.opsForValue();
            String redisToken = (String) ops.get(loginWay + "-access_token::" + username);
            if (token.equals(redisToken)) {//token验证通过
                response.getHeaders().add("access_token",token);//放入响应
                response.getHeaders().add("Access-Control-Expose-Headers","access_token");
                List<UrlInfo> urlInfos = (List<UrlInfo>) ops.get("permission::" + username);
                if (urlInfos == null) {//Redis中没有就去数据库中查
                    urlInfos = userService.getUserPermission(username);
                    List<UrlInfo> exclude = userService.getExcludeUrl();
                    urlInfos.addAll(exclude);
                    ops.set("permission::" + username, urlInfos, 10, TimeUnit.MINUTES);
                }
                boolean hasPermission = false;//默认没有权限
                if (loginWay.equals("APP/LS")) hasPermission = true;
                if (comparison(urlInfos,url,method)){
                    hasPermission = true;
                }

                if (hasPermission) {//有权限
                    ServerWebExchange newExchange = exchange.mutate().request(newRequest).response(response).build();
                    return chain.filter(newExchange);
                } else {//没有权限
                    return ResponseUtil.writeError(response,103,"没有权限");
                }
            } else {//token验证未通过
                return ResponseUtil.writeError(response,102,"用户认证未通过");
            }
        } catch (Exception e) {//token解析错误
            e.printStackTrace();
            return ResponseUtil.writeError(response,102,"无效的票据");
        }

    }

    @Override
    public int getOrder() {
        return -1;
    }

    private boolean comparison(List<UrlInfo> urlInfos,String url,String method) {
        AntPathMatcher matcher = new AntPathMatcher();
        for (UrlInfo urlInfo : urlInfos) {
            String redisUrl = urlInfo.getUrl();
            String[] dbUrls;
            String[] dbMethods;
            if (redisUrl.contains(",")){
                dbUrls = redisUrl.split(",");
                dbMethods = urlInfo.getMethod().split(",");
            } else {
                dbUrls = new String[]{redisUrl};
                dbMethods = new String[]{urlInfo.getMethod()};
            }
            for (int i = 0; i < dbUrls.length; i++) {
                if (matcher.match(dbUrls[i],url)&&method.equalsIgnoreCase(dbMethods[i])){
                    return true;
                }
            }
        }
        return false;
    }
}
